package org.example.page;

import io.ebean.typequery.IQueryBean;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * 简单的分页请求参数对象，继承自 SortParam 以包含排序功能。
 * 用于封装客户端发来的分页和排序请求信息。
 */
public class PageParam extends SortParam {
    private static final int DEFAULT_PAGE_NUMBER = 1; // 默认页码 (基于 1)
    private static final int DEFAULT_PAGE_SIZE = 20;   // 默认每页大小

    /**
     * 请求的页码 (基于 1 开始计数)
     */
    private int pageNumber;

    /**
     * 请求的每页大小
     */
    private int pageSize;

    public void setPageNumber(int pageNumber) {
        this.pageNumber = pageNumber;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    /**
     * 使用默认值创建 PageParam (页码 1, 大小 10, 不排序)
     */
    public PageParam() {
        this(DEFAULT_PAGE_NUMBER, DEFAULT_PAGE_SIZE, DEFAULT_SORT); // 使用 SortParam 的 DEFAULT_SORT
    }

    /**
     * 指定页码和大小，使用默认排序 (不排序)
     *
     * @param pageNumber 页码 (>= 1)
     * @param pageSize   每页大小 (>= 1)
     */
    public PageParam(int pageNumber, int pageSize) {
        this(pageNumber, pageSize, DEFAULT_SORT); // 使用 SortParam 的 DEFAULT_SORT
    }

    /**
     * 指定页码、大小和排序规则
     *
     * @param pageNumber 页码 (>= 1)
     * @param pageSize   每页大小 (>= 1)
     * @param sort       排序规则列表 (可以为 null 或空)
     */
    public PageParam(int pageNumber, int pageSize, List<Order> sort) {
        super(sort); // 调用父类构造函数来处理排序
        if (pageNumber < 1) {
            throw new IllegalArgumentException("Page number must be greater than or equal to 1!");
        }
        if (pageSize < 1) {
            throw new IllegalArgumentException("Page size must be greater than or equal to 1!");
        }
        this.pageNumber = pageNumber;
        this.pageSize = pageSize;
    }

    /**
     * 静态工厂方法 - 指定页码和大小，不排序
     *
     * @param pageNumber 页码 (>= 1)
     * @param pageSize   每页大小 (>= 1)
     * @return PageParam 实例
     */
    public static PageParam of(int pageNumber, int pageSize) {
        return new PageParam(pageNumber, pageSize);
    }

    /**
     * 静态工厂方法 - 指定页码、大小和排序规则 (使用 Order 对象列表)
     *
     * @param pageNumber 页码 (>= 1)
     * @param pageSize   每页大小 (>= 1)
     * @param sort       排序规则列表
     * @return PageParam 实例
     */
    public static PageParam of(int pageNumber, int pageSize, List<Order> sort) {
        return new PageParam(pageNumber, pageSize, sort);
    }

    /**
     * 静态工厂方法 - 指定页码、大小和排序规则 (使用可变参数 Order 对象)
     *
     * @param pageNumber 页码 (>= 1)
     * @param pageSize   每页大小 (>= 1)
     * @param orders     排序规则 (可变参数)
     * @return PageParam 实例
     */
    public static PageParam of(int pageNumber, int pageSize, Order... orders) {
        return new PageParam(pageNumber, pageSize, Arrays.asList(orders));
    }

    /**
     * 获取请求的页码 (基于 1)
     *
     * @return 页码
     */
    public int getPageNumber() {
        return pageNumber;
    }

    /**
     * 获取请求的每页大小
     *
     * @return 每页大小
     */
    public int getPageSize() {
        return pageSize;
    }

    /**
     * 获取用于数据库查询的偏移量 (Offset)
     * 通常 Offset = (页码 - 1) * 每页大小
     *
     * @return 偏移量 (基于 0)
     */
    public int getOffset() {
        // 页码从 1 开始，偏移量从 0 开始
        return (pageNumber - 1) * pageSize;
    }

    // getSort() 和 hasSort() 方法现在从 SortParam 继承

    @Override
    public String toString() {
        // 调用父类的 toString 获取排序部分，并组合自己的信息
        return String.format("PageParam [pageNumber=%d, pageSize=%d, sort=%s]",
                pageNumber, pageSize, super.toString());
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        // 注意：这里不使用 getClass() != o.getClass()，因为我们可能期望 PageParam 等于包含相同排序的 SortParam
        // 如果需要严格类型匹配，则使用 getClass() != o.getClass()
        // if (o == null || getClass() != o.getClass()) return false;
        if (o == null) return false; // 至少要是 SortParam 或其子类
        if (!(o instanceof PageParam other)) return false; // 必须是 PageParam 实例才能比较 pageNumber 和 pageSize

        // 先比较父类的部分 (sort)，再比较子类自己的字段
        return super.equals(o) &&
                pageNumber == other.pageNumber &&
                pageSize == other.pageSize;
    }

    @Override
    public int hashCode() {
        // 结合父类的 hashCode 和自己的字段
        return Objects.hash(super.hashCode(), pageNumber, pageSize);
    }

    /**
     * 应用分页规则到查询对象 该方法依赖于 QueryBean 接口，
     * 该接口是 Ebean 提供的用于构建查询的抽象。
     * 它允许我们在查询中指定分页和排序规则，而无需直接编写 SQL。
     * 这个方法会自动设置查询的 firstRow 和 maxRows 属性，
     *
     * @param query
     * @param <T>
     * @param <R>
     */

    public <T, R extends IQueryBean<T, R>> void applyPage(IQueryBean<T, R> query) {
        query.setFirstRow(this.getOffset()).setMaxRows(this.getPageSize());
    }
}
